package hibatis.support.parse;

import hibatis.Direction;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Created by huangdachao on 2018/6/28 18:25.
 */
public class PageAndSort {
    private Long limit;
    private Long offset;
    private String limitPlaceholder;
    private String offsetPlaceholder;
    private List<SortMeta> sort = new ArrayList<>();
    private boolean selectOne;
    private boolean selectCount;

    public String toSql(Map<Table, String> tblAlias) {
        StringBuilder sql = new StringBuilder();
        if (!selectCount) {
            if (sort != null && sort.size() > 0) {
                sql.append(" order by ");
                boolean first = true;
                for (SortMeta sort : sort) {
                    if (first) {
                        first = false;
                    } else {
                        sql.append(",");
                    }
                    sql.append(tblAlias.get(sort.getTableColumn().toTable())).append(".")
                        .append(sort.getTableColumn().column).append(" ")
                        .append(sort.getDirection().name());
                }
            }

            if (limit != null) {
                sql.append(" limit ").append(limit);
            } else if (limitPlaceholder != null) {
                sql.append(" limit ").append("#{").append(limitPlaceholder).append("}");
            }

            if (offset != null) {
                sql.append(" offset ").append(offset);
            } else if (offsetPlaceholder != null) {
                sql.append(" offset ").append("#{").append(offsetPlaceholder).append("}");
            }
        }
        return sql.toString();
    }

    public Long getLimit() {
        return limit;
    }

    public void setLimit(Long limit) {
        this.limit = limit;
    }

    public Long getOffset() {
        return offset;
    }

    public void setOffset(Long offset) {
        this.offset = offset;
    }

    public String getLimitPlaceholder() {
        return limitPlaceholder;
    }

    public void setLimitPlaceholder(String limitPlaceholder) {
        this.limitPlaceholder = limitPlaceholder;
    }

    public String getOffsetPlaceholder() {
        return offsetPlaceholder;
    }

    public void setOffsetPlaceholder(String offsetPlaceholder) {
        this.offsetPlaceholder = offsetPlaceholder;
    }

    public List<SortMeta> getSort() {
        return sort;
    }

    public void setSort(List<SortMeta> sort) {
        this.sort = sort;
    }

    public boolean isSelectOne() {
        return selectOne;
    }

    public void setSelectOne(boolean selectOne) {
        this.selectOne = selectOne;
    }

    public boolean isSelectCount() {
        return selectCount;
    }

    public void setSelectCount(boolean selectCount) {
        this.selectCount = selectCount;
    }

    public static class SortMeta {
        private final TableColumn tableColumn;
        private final Direction direction;

        public SortMeta(TableColumn tableColumn, Direction direction) {
            this.tableColumn = tableColumn;
            this.direction = direction;
        }

        public static List<SortMeta> parseSort(EntityMeta em, String sort) {
            return Arrays.stream(sort.split(",")).map(str -> {
                String[] arr = str.trim().split("\\s+");
                if (arr.length > 2) {
                    throw new RuntimeException("无法解析的排序参数：" + sort);
                }

                TableColumn tc = TableColumn.parse(arr[0], em);
                if (tc == null) {
                    throw new RuntimeException("无法解析的排序参数：" + sort);
                }

                Direction direction;
                if (arr.length == 1) {
                    direction = Direction.asc;
                } else {
                    String order = arr[1].toLowerCase();
                    if (Direction.asc.name().equals(order)) {
                        direction = Direction.asc;
                    } else if (Direction.desc.name().equals(order)) {
                        direction = Direction.desc;
                    } else {
                        throw new RuntimeException("无法解析的排序参数：" + sort);
                    }
                }
                return new SortMeta(tc, direction);
            }).collect(Collectors.toList());
        }

        public TableColumn getTableColumn() {
            return tableColumn;
        }

        public Direction getDirection() {
            return direction;
        }
    }
}
